<?php
define('_CookieKey_', 'CookieKey');
define('_RBACCookieKey_', 'RBACUser');
define('_RBACMerchantCookieKey_', 'RBACMerchantUser');
define('_EXPIRETIME_', 86000);

define('_COOKIE_KEY_', 'f6j5r@ziqpei&vkjapip19lo6kl8t4');
define('_COOKIE_IV_', 'x6j5r@ziqpei&vkjapip19lo6kl8t3');

define('APP_KEY', '');
define('APP_SECRET', '');

define('ENCRYPT_KEY', 'General.2021022');
define('ENCRYPT_IV', '63ssa6d5f4Xzhf&797d4f.g$t96bae20');

define('LOG_DIR', APP_PATH . '/logs/');
define('CERT_DIR', APP_PATH . '/cert/');
define('MAXROWS', 300000);

#捕获Warring错误
set_error_handler('displayErrorHandler');
function displayErrorHandler($errno, $errstr, $filename, $line)
{
    $error_no_arr = [
        1    => 'ERROR',
        2    => 'WARNING',
        4    => 'PARSE',
        8    => 'NOTICE',
        16   => 'CORE_ERROR',
        32   => 'CORE_WARNING',
        64   => 'COMPILE_ERROR',
        128  => 'COMPILE_WARNING',
        256  => 'USER_ERROR',
        512  => 'USER_WARNING',
        1024 => 'USER_NOTICE',
        2047 => 'ALL',
        2048 => 'STRICT'
    ];

    if (in_array($errno, [1, 2, 4])) {
        Log::out("File:{$filename} on Line:{$line} \n" . $error_no_arr[$errno] . ":" . $errstr . "\n", 'error');
        #throw new \Exception($error_no_arr[$errno] . ":". $errstr, $errno);
    }
}

/**
 * 输出变量的内容，通常用于调试
 *
 * @param mixed $vars 要输出的变量
 * @param string $label
 * @param boolean $return
 * @package Core
 *
 */
if (!function_exists('dump')) {
    function dump($vars, $label = '', $return = false)
    {
        if (php_sapi_name() != 'cli') {
            if (ini_get('html_errors')) {
                $content = "<pre>" . PHP_EOL;
                if ($label != '') {
                    $content .= "<strong>{$label} :</strong>" . PHP_EOL;
                }
                $content .= htmlspecialchars(print_r($vars, true));
                $content .= PHP_EOL . "</pre>" . PHP_EOL;
            } else {
                if ($label != '') {
                    $content = $label . " :" . PHP_EOL;
                }
                $content .= print_r($vars, true);
            }
            if ($return) {
                return $content;
            }
            echo $content;
        } else {
            print_r($vars);
            echo PHP_EOL;
        }
        return null;
    }
}

function json($vars = [], $format = 'json', $callback = 'callback', $updateNull = true)
{
    if ($format == 'json') {
        header("Content-type: application/json;charset=utf-8");
        $data = $updateNull ? updateNull($vars) : $vars;
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
    } else {
        header("Content-type: text/javascript;charset=utf-8");
        $data = $updateNull ? updateNull($vars) : $vars;
        echo "{$callback}(" . json_encode($data, JSON_UNESCAPED_UNICODE) . ")";
    }
}

function jsonp($data, int $code = 200)
{
    http_response_code($code);
    if ($code != 200) {
        $data = ['msg' => $data];
    }
    json($data);
}

function ret($ret = 0, $msg = 'ok', $data = null)
{
    $ret = [
        'ret' => $ret,
        'msg' => $msg,
    ];
    if (!empty($data)) {
        $ret['data'] = $data;
    }
    json($ret);
    exit;
}

function updateNull(&$onearr)
{
    if (!empty($onearr) && is_array($onearr)) {
        foreach ($onearr as $k => $v) {
            if (is_array($v)) {
                $onearr[$k] = updateNull($v);
            } else {
                if ($v === NULL) {
                    $onearr[$k] = '';
                }
            }
        }
    }
    return $onearr;
}

/***保存SQL记录到redis***/
function remember($key, $ttl, callable $func)
{
    $cache_enable = Yaf_Registry::get('config')->cache->redis->enable;
    if ($cache_enable && Cache::exists($key)) {
        return Cache::get($key);
    }
    $rows = call_user_func($func);
    if ($cache_enable) {
        Cache::set($key, $rows, $ttl);
    }
    return $rows;
}

/***遗忘***/
function forget($key)
{
    $cache_enable = Yaf_Registry::get('config')->cache->redis->enable;
    if ($cache_enable && Cache::exists($key)) {
        Cache::delete($key);
    }
}

/***redis同步锁***/
function sync($key, callable $func, $expire = 10000)
{
    $cache_enable = Yaf_Registry::get('config')->cache->redis->enable;
    if (!$cache_enable) {
        $result = call_user_func($func);
    }else {
        $random = uniqid($key) . rand(0, 1000000);
        while (TRUE) {
            if (Cache::setNex($key, $random, $expire)){
                break;
            }
            usleep(200000);
        }
        $result = call_user_func($func);
        if (Cache::get($key) == $random) {
            Cache::delete($key);
        }
    }

    return $result;
}

#获取请求头
function getHeader($key = '')
{
    if ($key == '') {
        $headers = [];
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                $headers[strtolower(substr($name, 5))] = $value;
            }
        }
        return $headers;
    } else {
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_' && strtolower($key) == strtolower(substr($name, 5))) {
                return $value;
            }
        }
    }
}

/***PHP上传文件到七牛cdn**
 * @param $filePath string 上传文件的本地路径
 * @param $cdnfileName string 上传到七牛后保存的文件名
 * @return false|string
 * @throws Exception
 */
function putToCDN(string $filePath, string $cdnfileName)
{
    $cdnCfg    = \configModel::where('type', 4)->pluck('value', 'key');
    $accessKey = $cdnCfg['accessKey'];
    $secretKey = $cdnCfg['secretKey'];
    $bucket    = $cdnCfg['bucket'];
    $url       = $cdnCfg['url'];

    // 生成上传 Token
    $token = remember('qiniuToken', 3600, function () use ($accessKey, $secretKey, $bucket) {
        // 构建鉴权对象
        $auth = new \Qiniu\Auth($accessKey, $secretKey);
        // 要上传的空间
        return $auth->uploadToken($bucket);
    });
    // 初始化 UploadManager 对象并进行文件的上传
    $uploadMgr = new \Qiniu\Storage\UploadManager;
    // 调用 UploadManager 的 putFile 方法进行文件的上传
    [$ret, $err] = $uploadMgr->putFile($token, $cdnfileName, $filePath);
    if ($err !== null) {
        Log::out($err->error, 'qiniu');
        return false;
    } else {
        $url = $url . $ret['key'];
        Hook::emit('file_upload_success', ['remote_url' => $url, 'file_size' => filesize($filePath)]);
        return $url;
    }
}

#上传base64图片字符串
function uploadImgByBase64(string $base64str)
{
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64str, $base64result)) {
        $ext      = $base64result[2];
        $ext      = stristr($ext, 'jpeg') ? 'jpg' : $ext;
        $config   = Yaf_Registry::get('config');
        $fileName = 'img-t' . time() . rand(10000, 99999) . '.' . $ext;
        $path     = '/uploads/' . date('Ym') . '/';
        $desdir   = $config->application->uploadpath . $path;
        if (!is_dir($desdir)) {
            mkdir($desdir, 0777, TRUE);
        }
        $realpath = $desdir . $fileName;

        if (file_put_contents($realpath, base64_decode(str_replace(' ', '+', str_replace($base64result[1], '', $base64str))))) {
            if ($image = putToCDN($desdir . $fileName, $fileName)) {
                return $image;
            }
        }
    }
    return FALSE;
}

/***上传图片文件**
 * @param $upfile
 * @return array|bool
 * @throws Exception
 */
function uploadImgByFile(string $upfile)
{
    $files = Yaf_Dispatcher::getInstance()->getRequest()->getFiles($upfile);
    if ($files != NULL && $files['size'] > 0) {
        $uploader = new FileUploader();
        $files    = $uploader->getFile($upfile);
        if (!$files) {
            return FALSE;
        }
        if ($files->getSize() == 0) {
            return FALSE;
        }
        $config = Yaf_Registry::get('config');
        if (!$files->checkExts($config->application->upfileExts)) {
            return FALSE;
        }
        if (!$files->checkSize($config->application->upfileSize)) {
            return FALSE;
        }
        $cdnfilename = 'Images-t' . time() . rand(100, 999) . '.' . $files->getExt();
        if ($image = putToCDN($files->getTmpName(), $cdnfilename)) {
            $rows = [
                "originalName" => $files->getFilename(),
                "name"         => $cdnfilename,
                "url"          => $image,
                "size"         => $files->getSize(),
                "type"         => $files->getMimeType(),
                "state"        => 'SUCCESS'
            ];
            return $rows;
        }
    }
    return FALSE;
}

function getIp()
{
    if (@$_SERVER["HTTP_X_FORWARDED_FOR"])
        $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
    else if (@$_SERVER["HTTP_CLIENT_IP"])
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    else if (@$_SERVER["REMOTE_ADDR"])
        $ip = $_SERVER["REMOTE_ADDR"];
    else if (@getenv("HTTP_X_FORWARDED_FOR"))
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    else if (@getenv("HTTP_CLIENT_IP"))
        $ip = getenv("HTTP_CLIENT_IP");
    else if (@getenv("REMOTE_ADDR"))
        $ip = getenv("REMOTE_ADDR");
    else
        $ip = "Unknown";
    return $ip;
}

/**
 * PHP生成随机字符串
 * @param int $length
 * @param int $type [0:全类型 1:数字 2:小写字母 3:小字字母+数字 4:大写字母 5:大字字母+数字]
 * @return string
 */
function randStr($length = 10, $type = 0): string
{
    switch ($type) {
        case 1:
            $characters = '1234567890';
            break;
        case 2:
            $characters = 'abcdefghijkmnopqrstuvwxyz';
            break;
        case 3:
            $characters = '1234567890abcdefghijkmnopqrstuvwxyz';
            break;
        case 4:
            $characters = 'ABCDEFGHIJKLMNPOQRSTUVWXYZ';
            break;
        case 5:
            $characters = '1234567890ABCDEFGHIJKLMNPOQRSTUVWXYZ';
            break;
        default:
            $characters = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ';
            break;
    }
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

/**
 * 跳转
 *
 * @param      $url
 * @param null $headers
 */
function redirect($url)
{
    echo "<script>top.location.href='{$url}';</script>";
    exit;
    /* if (!empty($url))
    {
        if ($headers)
        {
            if (!is_array($headers))
                $headers = array($headers);

            foreach ($headers as $header)
                header($header);
        }

        header('Location: ' . $url);
        exit;
    } */
}

function pick(string $url, $postData = '')
{
    $row  = parse_url($url);
    $host = $row['host'];
    $port = isset($row['port']) ? $row['port'] : 80;
    $file = $row['path'];
    if (is_array($postData)) {
        $postData = http_build_query($postData);
    }
    $len = strlen($postData);
    $fp  = @fsockopen($host, $port, $errno, $errstr, 10);
    if (!$fp) {
        return "$errstr ($errno)\n";
    } else {
        $receive = '';
        $out     = "POST $file HTTP/1.1\r\n";
        $out     .= "Host: $host\r\n";
        $out     .= "Content-type: application/x-www-form-urlencoded\r\n";
        $out     .= "Connection: Close\r\n";
        $out     .= "Content-Length: $len\r\n\r\n";
        $out     .= $postData;
        fwrite($fp, $out);
        while (!feof($fp)) {
            $receive .= fgets($fp, 128);
        }
        fclose($fp);
        $receive = explode("\r\n\r\n", $receive);
        unset($receive[0]);
        return implode("", $receive);
    }
}

/**
 *curl采集函数
 * @param string $url
 * @param string $postData
 * @param array $header
 * @param string $referer
 * @param bool $proxyip
 * @param string $compression
 * @return bool|string
 */
function request(string $url, $postData = '', $header = [], $referer = 'http://www.baidu.com', $proxyip = false, $compression = 'gzip, deflate')
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    if (!empty($header)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    }
    if (!empty($postData)) {
        curl_setopt($ch, CURLOPT_POST, 1);
        if (is_array($postData)) {
            $postData = http_build_query($postData);
        }
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    }
    if (!empty($proxyip)) {
        curl_setopt($ch, CURLOPT_PROXY, $proxyip);
    }
    if (!empty($compression)) {
        curl_setopt($ch, CURLOPT_ENCODING, $compression);
    }
    curl_setopt($ch, CURLOPT_REFERER, $referer ?? "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11');
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

function curl_json($url, $jsonStr, $header = [])
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $json_header = [
        'Content-Type: application/json; charset=utf-8',
        'Content-Length: ' . strlen($jsonStr),
    ];
    $header      = array_merge($header, $json_header);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $response = curl_exec($ch);
    #$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    return $response;
}

/**
 * 数组 转 对象
 *
 * @param array $arr 数组
 * @return object
 */
function array_to_object($arr)
{
    if (gettype($arr) != 'array') {
        return;
    }
    foreach ($arr as $k => $v) {
        if (gettype($v) == 'array' || getType($v) == 'object') {
            $arr[$k] = (object)array_to_object($v);
        }
    }
    return (object)$arr;
}

/**
 * 对象 转 数组
 *
 * @param object $obj 对象
 * @return array
 */
function object_to_array($obj)
{
    $obj = (array)$obj;
    foreach ($obj as $k => $v) {
        if (gettype($v) == 'resource') {
            return;
        }
        if (gettype($v) == 'object' || gettype($v) == 'array') {
            $obj[$k] = (array)object_to_array($v);
        }
    }
    return $obj;
}

/**
 * @param string $controller
 * @param string $module
 * @return string
 */
function controllerFile($controller = '', $module = 'index')
{
    $config = Yaf_Registry::get('config');
    if(!empty($controller)){
        if(preg_match('/^[A-Z][a-z]+(_[A-Z][a-z]+)+$/', $controller)){
            $controller = str_replace('_', '/', $controller);
        }
    }
    if (strcasecmp($module, 'index') === 0) {
        if (empty($controller)) {
            return $config->application->directory . '/controllers';
        } else {
            if(preg_match('/\+$/', $controller)){
                return $config->application->directory . '/controllers/'.str_replace('+', '', $controller);
            }else{
                return $config->application->directory . '/controllers/' . $controller . '.' . $config->application->ext;
            }
        }
    } else {
        if (empty($controller)) {
            return $config->application->directory . '/modules/' . $module . '/controllers';
        } else {
            if(preg_match('/\+$/', $controller)){
                return $config->application->directory . '/modules/' . $module . '/controllers/'.str_replace('+', '', $controller);
            }else{
                return $config->application->directory . '/modules/' . $module . '/controllers/' . $controller . '.' . $config->application->ext;
            }
        }
    }
}

function base32_encode(string $input): string
{
    $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
    $output          = '';
    $v               = 0;
    $vbits           = 0;

    for ($i = 0, $j = strlen($input); $i < $j; $i++) {
        $v     <<= 8;
        $v     += ord($input[$i]);
        $vbits += 8;

        while ($vbits >= 5) {
            $vbits  -= 5;
            $output .= $BASE32_ALPHABET[$v >> $vbits];
            $v      &= ((1 << $vbits) - 1);
        }
    }

    if ($vbits > 0) {
        $v      <<= (5 - $vbits);
        $output .= $BASE32_ALPHABET[$v];
    }

    return $output;
}

function base32_decode(string $input): string
{
    $output = '';
    $v      = 0;
    $vbits  = 0;

    for ($i = 0, $j = strlen($input); $i < $j; $i++) {
        $v <<= 5;
        if ($input[$i] >= 'a' && $input[$i] <= 'z') {
            $v += (ord($input[$i]) - 97);
        } elseif ($input[$i] >= '2' && $input[$i] <= '7') {
            $v += (24 + $input[$i]);
        } else {
            return '';
        }

        $vbits += 5;
        while ($vbits >= 8) {
            $vbits  -= 8;
            $output .= chr($v >> $vbits);
            $v      &= ((1 << $vbits) - 1);
        }
    }
    return $output;
}

function encode($data)
{
    $method = "AES-256-CBC";
    return base64_encode(openssl_encrypt($data, $method, ENCRYPT_KEY, OPENSSL_RAW_DATA, ENCRYPT_IV));
}

function decode($data)
{
    $method = "AES-256-CBC";
    return openssl_decrypt(base64_decode($data), $method, ENCRYPT_KEY, OPENSSL_RAW_DATA, ENCRYPT_IV);
}

/**
 * 字符串命名风格转换
 * type 0下划线 1驼峰
 * @access public
 * @param string $name 字符串
 * @param integer $type 转换类型
 * @param bool $ucfirst 首字母是否大写（驼峰规则）
 * @return string
 */
function parseName($name, $type = 0, $ucfirst = true)
{
    if ($type) {
        $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
            return strtoupper($match[1]);
        }, $name);

        return $ucfirst ? ucfirst($name) : lcfirst($name);
    }

    return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
}

/**
 * 获取上传资源的CDN的地址
 * @param string $url 资源相对地址
 * @param boolean $domain 是否显示域名 或者直接传入域名
 * @return string
 */
function cdnurl($url, $domain = false)
{
    return $url;
}

function trace($log = '', $strFileName = "trace")
{
    if (DEBUG_MODE) {
        Log::out($log, $strFileName);
    }
}

/**
 * 树形结构算法
 * @param array $data
 * @param string $key
 * @return array
 */
function get_tree($data, $key = 'pid', $val = 0)
{
    $tree = [];
    foreach ($data as $index => $item) {
        if ($item[$key] == $val) {
            $item['child_list']  = get_tree($data, $key, $item['id']);
            $item['child_count'] = count($item['child_list']);
            $item['children']    = $item['child_list'];
            $tree[]              = $item;
        }
    }
    return $tree;
}

function timestamp($time = null)
{
    return date('Y-m-d H:i:s', $time ?: time());
}

function syncFileBak($filepath)
{
    $fileinfo = pathinfo($filepath);
    $dirs     = preg_split('#[/\\\\]#', $fileinfo['dirname']);
    $config   = Yaf_Registry::get('config');
    if ($config->fileHost->enable) {
        $postData = [
            'token'     => md5($filepath . ENCRYPT_IV),
            'file_path' => $filepath,
            'file_body' => base64_encode(file_get_contents($filepath))
        ];
        $res      = json_decode(request($config->fileHost->api, $postData), true);
        if ($res['ret'] == 0) {
            return $config->fileHost->url . '/' . end($dirs) . '/' . $fileinfo['basename'];
        }
        return false;
    } else {
        return $config->application->hostUrl . '/' . end($dirs) . '/' . $fileinfo['basename'];
    }
}

function syncFile($filepath)
{
    $config = \Yaf_Application::app()->getConfig();
    $fileinfo = pathinfo($filepath);
    try {
        $key     = 'excel/' . date('Ymd') . '/' . explode('.', $fileinfo['basename'])[0] . randStr(8) . '.' . $fileinfo['extension'];
        $result  = putObject($config->application->cdn->api, $key, $filepath);
        if (!$result || $result['ret'] != 0) {
            throw new \Exception("同步文件失败， 请重试");
        }

        return $config->application->cdn->url . '/' . $result['data'];
    } catch (\Exception $e) {
        \Log::out($e->getMessage(), 'fileserver');
    }
}

function putObject($apiUrl, $key, $file)
{
    $header=array("Expect:","Cache-Control: no-cache","Content-Type: multipart/form-data");
    $full_path= $file;
    $post_data['key'] = $key;
    $post_data['file'] = new CurlFile($full_path);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $apiUrl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_ENCODING, "");
    curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
    curl_setopt($curl, CURLOPT_TIMEOUT, 300);
    curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
    if($header){
        curl_setopt($curl, CURLOPT_HTTPHEADER,$header);
    }
    $response = curl_exec($curl);
    \Log::out($response, 'fileserver');
    //        $err = curl_error($curl);
    //        if ($err) {
    //            echo "cURL Error #:" . $err;
    //        }
    curl_close($curl);

    $output_array = json_decode($response,true);
    return $output_array;
}

function carbon($dateTime = null)
{
    return new \Carbon\Carbon($dateTime);

}